#include "ringbuf.h"
#include "gkt_config.h"

#if defined(GKT_CONFIG_FPS_ENABLE) && GKT_CONFIG_FPS_ENABLE

static G_RingBuf_Size_t GetDataLen(G_pRingBuf_TyperDef pRingBuf)
{
    if (pRingBuf->WPtr < pRingBuf->RPtr)
    {
        return pRingBuf->BufSize - pRingBuf->RPtr + pRingBuf->WPtr;
    }
    else
    {
        return pRingBuf->WPtr - pRingBuf->RPtr;
    }
}

static G_Boolean IsEmpty(G_pRingBuf_TyperDef pRingBuf)
{
    if(pRingBuf->WPtr == pRingBuf->RPtr)
    {
        return TRUE;
    }
    return FALSE;
}

static G_Boolean IsFull(G_pRingBuf_TyperDef pRingBuf)
{
    if(((pRingBuf->BufSize - GetDataLen(pRingBuf)) == 1))
    {
        return TRUE;
    }
    return FALSE;
}

static G_Boolean put(G_pRingBuf_TyperDef pRingBuf, unsigned char *buf, G_RingBuf_Size_t len)
{
    G_RingBuf_Size_t WPtr = pRingBuf->WPtr;
    if (GetDataLen(pRingBuf) + len >= pRingBuf->BufSize || len == 0)
    {
        return FALSE;
    }

    while (len--)
    {
        pRingBuf->RingBufPool[WPtr] = *(unsigned char *)(buf++);
        ++WPtr;
        if (WPtr >= pRingBuf->BufSize)
        {
            WPtr = 0;
        }
    }
    pRingBuf->WPtr = WPtr;
    return TRUE;
}

static G_Boolean PutTry(G_pRingBuf_TyperDef pRingBuf, unsigned char *buf, G_RingBuf_Size_t len)
{
    G_RingBuf_Size_t WPtr = pRingBuf->WPtr;
    if (GetDataLen(pRingBuf) + len >= pRingBuf->BufSize || len == 0)
    {
        return FALSE;
    }

    while (len--)
    {
        pRingBuf->RingBufPool[WPtr] = *(unsigned char *)(buf++);
        ++WPtr;
        if (WPtr >= pRingBuf->BufSize)
        {
            WPtr = 0;
        }
    }
    return TRUE;
}

static G_Boolean get(G_pRingBuf_TyperDef pRingBuf, unsigned char *buf, G_RingBuf_Size_t len)
{
    G_RingBuf_Size_t RPtr = pRingBuf->RPtr;
    if (GetDataLen(pRingBuf) < len || len == 0)
    {
        return FALSE;
    }
    while (len--)
    {
        *(volatile unsigned char *)(buf++) = pRingBuf->RingBufPool[RPtr];
        ++RPtr;
        if (RPtr >= pRingBuf->BufSize)
        {
            RPtr = 0;
        }
    }
    pRingBuf->RPtr = RPtr; 
    return TRUE;
}

static G_Boolean GetTry(G_pRingBuf_TyperDef pRingBuf, unsigned char *buf, G_RingBuf_Size_t len)
{
    G_RingBuf_Size_t RPtr = pRingBuf->RPtr;

    if (GetDataLen(pRingBuf) < len || len == 0)
    {
        return FALSE;
    }

    while (len--)
    {
        *(volatile unsigned char *)(buf++) = pRingBuf->RingBufPool[RPtr];
        ++RPtr;
        if (RPtr >= pRingBuf->BufSize)
        {
            RPtr = 0;
        }
    }
    return TRUE;
}



const struct RingBuf_Func_TyperDef RingBuf_Func =
{
    put,
    get,
    IsEmpty,
    IsFull,
    GetDataLen,
    GetTry,
    PutTry,
};

G_pRingBuf_TyperDef G_RingBufCreat(uint8_t *baseAddr, G_RingBuf_Size_t size)
{
    G_pRingBuf_TyperDef pRingBuf = NULL;
    if (size < sizeof(G_RingBuf_TyperDef) + 2)
    {
        return NULL;
    }

    pRingBuf  = (G_pRingBuf_TyperDef)(baseAddr);
    pRingBuf->pRingBuf  = pRingBuf;
    pRingBuf->RingBufPool = (uint8_t *)((uint32_t)(baseAddr) + sizeof(G_RingBuf_TyperDef));
    pRingBuf->BufSize   = size - sizeof(G_RingBuf_TyperDef);
    pRingBuf->WPtr      = 0;
    pRingBuf->RPtr      = 0;
    return pRingBuf;
}

#endif
